package cn.donting.jme;

import cn.donting.jme.editor.EditorUI;
import cn.donting.jme.editor.ErrorCallback;
import cn.donting.jme.editor.clipboard.Clipboard;
import cn.donting.jme.editor.clipboard.ClipboardType;
import cn.donting.jme.editor.file.FileRefManager;
import cn.donting.jme.editor.scene.Scene;
import cn.donting.jme.event.EditorEventBus;
import cn.donting.jme.event.AbsEvent;
import cn.donting.jme.event.Event;
import cn.donting.jme.ioc.IocContainer;
import cn.donting.jme.project.Project;
import cn.donting.jme.utile.IdentityWeakHashMap;
import com.google.common.eventbus.EventBus;
import com.jme3.asset.AssetKey;
import com.jme3.asset.AssetManager;
import com.jme3.asset.CloneableSmartAsset;
import lombok.extern.slf4j.Slf4j;

import javax.swing.*;
import java.io.File;
import java.net.URL;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class EditorContent {
    static EditorFrame editorFrame;
    private static IocContainer iocContainer;
    private static EventBus eventBus;
    private static Project project;
    private static FileRefManager fileRefManager;
    /**
     * 当前编辑的场景
     */
    private static Scene scene;

    private static ExecutorService executorService;

    private static Clipboard clipboard;

    private static IdentityWeakHashMap<Object, Integer> objectIdMap = new IdentityWeakHashMap<>();
    private static IdentityWeakHashMap<Object, HashMap<String, Object>> objectDataMap = new IdentityWeakHashMap<>();
    private static int objectId = 1000;


    public static EditorUI getEditorUI() {
        return editorFrame;
    }

    public static JmeApplication getJmeApplication() {
        return getEditorUI().getJmeApplication();
    }

    public static void runJme(Runnable runnable) {
        if (getJmeApplication().isJmeThread()) {
            runnable.run();
            return;
        }
        getJmeApplication().enqueue(runnable);
    }

    public static void runSwing(Runnable runnable) {
        if (SwingUtilities.isEventDispatchThread()) {
            runnable.run();
            return;
        }
        SwingUtilities.invokeLater(runnable);
    }

    public static boolean isSwingThread() {
        if (SwingUtilities.isEventDispatchThread()) {
            return true;
        }
        return false;
    }

    public static void postEvent(Event event) {
        if (event==null) {
            return;
        }
        eventBus.post(event);
    }

    public static void registerEvent(Object sou) {
        eventBus.register(sou);
    }

    public static IocContainer getIocContainer() {
        return iocContainer;
    }

    public static void setScene(Scene scene) {
        EditorContent.scene = scene;
    }

    public static Scene getScene() {
        return scene;
    }

    public static Project getProject() {
        return project;
    }

    public static <T> T getAssetManagerFromCache(AssetKey<T> assetKey) {
        AssetManager assetManager = getJmeApplication().getAssetManager();
        T fromCache = assetManager.getFromCache(assetKey);
        if (fromCache == null) {
            assetManager.loadAsset(assetKey);
            fromCache = assetManager.getFromCache(assetKey);
        }
        if (fromCache instanceof CloneableSmartAsset) {
            ((CloneableSmartAsset) fromCache).setKey(assetKey);
        }
        return fromCache;
    }

    static void initContent(Project project) {
        EditorContent.project = project;
        fileRefManager = new FileRefManager();
        iocContainer = new IocContainer();
        eventBus = new EditorEventBus(iocContainer);
        executorService = Executors.newFixedThreadPool(5);

    }

    public static URL getResource(String name) {
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        URL resource = contextClassLoader.getResource(name);
        if (resource == null) {
            return project.getClassLoader().getResource(name);
        }
        return resource;
    }

    /**
     * 编辑数据目录
     *
     * @return
     */
    public static File getEditorDataDir() {
        File projectDir = getProject().getProjectDir();
        File file = new File(projectDir, ".editor");
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }

    public static FileRefManager getFileRefManager() {
        return fileRefManager;
    }

    public static void submitTask(Runnable runnable) {
        submitTask(runnable, ex -> {
            log.error(ex.getMessage(), ex);
        });
    }

    public static void submitTask(Runnable runnable, ErrorCallback taskCallback) {
        executorService.submit(() -> {
            try {
                runnable.run();
            } catch (Exception ex) {
                taskCallback.error(ex);
            }
        });
    }

    public static void setClipboard(Clipboard clipboard) {
        EditorContent.clipboard = clipboard;
    }

    public static void setClipboard(Object source, ClipboardType type) {
        EditorContent.clipboard = new Clipboard(source, type);
    }

    public static Clipboard getClipboard() {
        return EditorContent.clipboard;
    }

    public static synchronized String getObjectId(Object obj) {
        if(obj==null){
            return "";
        }
        Integer id = objectIdMap.get(obj);
        if (id == null) {
            id = objectId++;
            objectIdMap.put(obj, id);
        }
        return "@" + id;
    }

    public static synchronized void setObjectData(Object obj, String key, Object data) {
        if (obj == null) {
            return;
        }
        HashMap<String, Object> objectDataHashMap = objectDataMap.get(obj);
        if (objectDataHashMap == null) {
            objectDataHashMap = new HashMap<>();
            objectDataMap.put(obj, objectDataHashMap);
        }
        objectDataHashMap.put(key, data);
    }

    public static synchronized <T> T getObjectData(Object obj, String key) {
        HashMap<String, Object> objectDataHashMap = objectDataMap.get(obj);
        if (objectDataHashMap != null) {
            return (T) objectDataHashMap.get(key);
        }
        return null;
    }

}
